package es.uc3m.setichat.android;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Random;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Source;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;

import org.w3c.dom.Document;
import org.xml.sax.SAXException;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlSerializer;

import android.content.Context;
import android.content.res.AssetManager;
import android.util.Log;
import android.util.Xml;
import es.uc3m.setichat.clases.SeTIChatContact;
import es.uc3m.setichat.clases.SeTIChatMessage;

public class SeTIChatXMLController {
	private XmlSerializer s = null;
//	public static String server = "setichati@appspot.com";
//	public static String server = "testeadorseti2@appspot.com";
	public static String server = "gae-083838-073057-080668@appspot.com";
	
	public static String mobile = null; 
	
	public SeTIChatXMLController(){
		s = Xml.newSerializer();
	}
	
	public String generateRandomID(){
		String id = "";
		Random rand = new Random(System.currentTimeMillis());
		int aux;
		for(int i=0;i<32;i++){
			aux = rand.nextInt(16);
			switch(aux){
				case 10	:
					id += "a";
					break;
				case 11	:
					id += "b";
					break;
				case 12	:
					id += "c";
					break;
				case 13	:
					id += "d";
					break;
				case 14	:
					id += "e";
					break;
				case 15	:
					id += "f";	
					break;
				default	:
					id += String.valueOf(aux);	
					break;
				
			}
		}
		
		return id;
		
	}
	
	private void createHeader(String idDestination,String idMenssage,String type,String encrypted,String signed){
		try {
			s.startTag(null,"header");
				s.startTag(null,"idSource");
					s.text(mobile);
				s.endTag(null,"idSource");
				s.startTag(null,"idDestination");
					s.text(idDestination); 
				s.endTag(null,"idDestination");
				s.startTag(null,"idMessage");
					s.text(idMenssage); 
				s.endTag(null,"idMessage");
				s.startTag(null,"type");
					s.text(type); 
				s.endTag(null,"type");
				s.startTag(null,"encrypted");
					s.text(encrypted); 
				s.endTag(null,"encrypted");
				s.startTag(null,"signed");
					s.text(signed); 
				s.endTag(null,"signed");
			s.endTag(null,"header");
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (IllegalStateException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		
	}
	
	public String createContactRequest(SeTIChatContact[] contactos,String message_id){
		
		ByteArrayOutputStream xml = new ByteArrayOutputStream();
		try {
			s.setOutput(xml, "UTF-8");
			s.startDocument(null,null);
//			s.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
				
			s.startTag(null,"message");
				createHeader(server,message_id,"2","false","false"); 
				s.startTag(null,"content");
					s.startTag(null,"mobileList");
						for(int i=0;i<contactos.length;i++){
							s.startTag(null,"mobile");
								s.text(contactos[i].mobile); 
							s.endTag(null,"mobile");
						}
					s.endTag(null,"mobileList");
				s.endTag(null,"content");
			s.endTag(null,"message");
			s.endDocument();
			s.flush();
			
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (IllegalStateException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		return xml.toString();
	}
	
	public String createChatMEssage(String idDestination,String message,String message_id,boolean encrypted,boolean signed){
		ByteArrayOutputStream xml = new ByteArrayOutputStream();
		try {
			s.setOutput(xml, "UTF-8");
			s.startDocument(null,null);
//			s.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
				
			s.startTag(null,"message");
				createHeader(idDestination,message_id,"4",encrypted ? "true" : "false",signed ? "true" : "false");
				s.startTag(null,"content");
					s.startTag(null,"chatMessage");
							s.text(message); 
					s.endTag(null,"chatMessage");
				s.endTag(null,"content");
			s.endTag(null,"message");
			s.endDocument();
			s.flush();
			
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (IllegalStateException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		if(signed){
			return _createChatMEssage(idDestination,message,message_id,encrypted,signed,SeTIChatCertificatesController.signed(xml.toString()));
		}
		
		return xml.toString();
	}
	
	public String _createChatMEssage(String idDestination,String message,String message_id,boolean encrypted,boolean signed,String sign){
		ByteArrayOutputStream xml = new ByteArrayOutputStream();
		try {
			s.setOutput(xml, "UTF-8");
			s.startDocument(null,null);
//			s.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
				
			s.startTag(null,"message");
				createHeader(idDestination,message_id,"4",encrypted ? "true" : "false",signed ? "true" : "false");
				s.startTag(null,"content");
					s.startTag(null,"chatMessage");
							s.text(message); 
					s.endTag(null,"chatMessage");
				s.endTag(null,"content");
				if(signed){
					s.startTag(null,"signature");
						s.text(sign); 
					s.endTag(null,"signature");
				}
			s.endTag(null,"message");
			s.endDocument();
			s.flush();
			
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (IllegalStateException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		return xml.toString();
	}
	
	public String createConnection(String message_id){
		ByteArrayOutputStream xml = new ByteArrayOutputStream();
		try {
			s.setOutput(xml, "UTF-8");
			s.startDocument(null,null);
//			s.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
				
			s.startTag(null,"message");
				createHeader(server,message_id,"5","false","false");
				s.startTag(null,"content");
					s.startTag(null,"connection");
					s.endTag(null,"connection");
				s.endTag(null,"content");
			s.endTag(null,"message");
			s.endDocument();
			s.flush();
			
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (IllegalStateException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		return xml.toString();
	}
	
	public String createSignUp(String message_id,String nick){
		ByteArrayOutputStream xml = new ByteArrayOutputStream();
		try {
			s.setOutput(xml, "UTF-8");
			s.startDocument(null,null);
//			s.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
				
			s.startTag(null,"message");
				createHeader(server,message_id,"1","false","false");
				s.startTag(null,"content");
					s.startTag(null,"signup");
						s.startTag(null,"nick");
							s.text(nick); 
						s.endTag(null,"nick");
						s.startTag(null,"mobile");
							s.text(mobile); 
						s.endTag(null,"mobile");
					s.endTag(null,"signup");
				s.endTag(null,"content");
			s.endTag(null,"message");
			s.endDocument();
			s.flush();
			
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (IllegalStateException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		return xml.toString();
	}
	
	public String createUpload(String typeCert, String certificate, String message_id){
		ByteArrayOutputStream xml = new ByteArrayOutputStream();
		try {
			s.setOutput(xml, "UTF-8");
			s.startDocument(null,null);
//			s.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
				
			s.startTag(null,"message");
				createHeader(server,message_id,"9","false","false");
				s.startTag(null,"content");
					s.startTag(null,"upload");
						s.startTag(null,"certificate");
							s.text(certificate); 
						s.endTag(null,"certificate");
						s.startTag(null,"type");
							s.text(typeCert); 
						s.endTag(null,"type");
					s.endTag(null,"upload");
				s.endTag(null,"content");
			s.endTag(null,"message");
			s.endDocument();
			s.flush();
			
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (IllegalStateException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		return xml.toString();
	}
	
	public String createCertificateRequest(String typeCert, String mobile, String message_id){
		ByteArrayOutputStream xml = new ByteArrayOutputStream();
		try {
			s.setOutput(xml, "UTF-8");
			s.startDocument(null,null);
//			s.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
				
			s.startTag(null,"message");
				createHeader(server,message_id,"10","false","false");
				s.startTag(null,"content");
					s.startTag(null,"certificaterequest");
						s.startTag(null,"type");
							s.text(typeCert); 
						s.endTag(null,"type");
						s.startTag(null,"mobile");
							s.text(mobile); 
						s.endTag(null,"mobile");
						
					s.endTag(null,"certificaterequest");
				s.endTag(null,"content");
			s.endTag(null,"message");
			s.endDocument();
			s.flush();
			
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (IllegalStateException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		return xml.toString();
	}
	
	
	
	public boolean validateSchema(String xmlMessage,Context context){
		// parse an XML document into a DOM tree
	    DocumentBuilderFactory parserFactory = DocumentBuilderFactory.newInstance();
	    parserFactory.setNamespaceAware(true);
	    DocumentBuilder parser;
	    Document document = null;
		try {
			parser = parserFactory.newDocumentBuilder();
			document = parser.parse(new ByteArrayInputStream(xmlMessage.getBytes()));
			
			// create a SchemaFactory capable of understanding WXS schemas

		    SchemaFactory factory = SchemaFactory.newInstance("http://www.w3.org/2001/XMLSchema");
		    // load a WXS schema, represented by a Schema instance
		    AssetManager assetManager = context.getAssets();
		    Source schemaFile = new StreamSource(assetManager.open("SeTIChatXMLSchema.xsd"));
		    Schema schema = factory.newSchema(schemaFile);
		    
		    // create a Validator instance, which can be used to validate an instance document
		    Validator validator = schema.newValidator();
		    // validate the DOM tree
		    validator.validate(new DOMSource(document));
		    
		    return true;
		} catch (SAXException e) {
			e.printStackTrace();
			Log.e("xml-validation","error");
		} catch (Exception e2) {
			e2.printStackTrace();
			Log.e("xml-validation","error");
			
		} 
		return false;
	    
	}
	
	public SeTIChatMessage parserXML(String xmlMessage) throws Exception{
		XmlPullParser parser = Xml.newPullParser();
		SeTIChatMessage message = new SeTIChatMessage();
		int evento = 0;
		try{
			parser.setInput(new ByteArrayInputStream(xmlMessage.getBytes()), null);
			evento = parser.getEventType();
			SeTIChatContact contact = null;
			String etiqueta = null;
			while (evento != XmlPullParser.END_DOCUMENT){
				 etiqueta = parser.getName();
				 switch(evento){
					 case XmlPullParser.START_TAG:
						 
						 if(etiqueta.equals("type") &&  message.header.getType() == 0){
							 message.header.setType(Integer.parseInt(parser.nextText()));
							 message.createContent();
							 break;
						 }else if(etiqueta.equals("idSource")){
							 message.header.setIdSource(parser.nextText());
						 }else if(etiqueta.equals("idDestination")){
							 message.header.setIdDestination(parser.nextText());
						 }else if(etiqueta.equals("idMessage")){
							 message.header.setIdMessage(parser.nextText());
						 }else if(etiqueta.equals("encrypted")){
							 message.header.setEncrypted(parser.nextText().equals("true") ? true : false);
						 }else if(etiqueta.equals("signed")){
							 message.header.setSigned(parser.nextText().equals("true") ? true : false);
						 }else if(etiqueta.equals("signature")){
							 message.setSignature(parser.nextText());
						 }
						 
						 switch(message.header.getType()){
						 	case 0	: break; 
						 	
						 	case 3	:	//ContactResponse
						 		if(etiqueta.equals("contactList")){
						 			message.content_validate = true;
						 		}else if(etiqueta.equals("contact")){
						 			contact = new SeTIChatContact();
						 		}else if(etiqueta.equals("mobile")){
						 			contact.setMobile(parser.nextText());
						 		}else if(etiqueta.equals("nick")){
						 			contact.setNick(parser.nextText());
						 		}
						 		break;
						 		
						 	case 4	: 	//ChatMessage
						 		if(etiqueta.equals("chatMessage")){
						 			message.content_validate = true;
						 			message.content.chatMessage.setMessage(parser.nextText());
						 		}
						 		break;
						 		
						 	case 6	:	//Response
						 		if(etiqueta.equals("responseCode")){
						 			message.content_validate = true;
						 			message.content.response.setResponseCode(Integer.parseInt(parser.nextText()));
						 		}else if(etiqueta.equals("responseMessage")){
						 			message.content.response.setResponseMessage(parser.nextText());
						 		}
						 		break;
						 		
						 	case 7	:	//Revocation
						 		if(etiqueta.equals("revokedMobile")){
						 			message.content_validate 	= true;
						 			message.content.revocation 	= parser.nextText();
						 		}
						 		break;
						 		
						 	case 8  :	//Download
						 		if(etiqueta.equals("certificate")){
						 			message.content_validate = true;
						 			message.content.download.setCertificate(parser.nextText());
						 		}else if(etiqueta.equals("type")){
						 			message.content.download.setType(parser.nextText());
						 		}else if(etiqueta.equals("mobile")){
						 			message.content.download.setMobile(parser.nextText());
						 		}
						 		break;
						 }
						 
						 break;
					 case XmlPullParser.END_TAG:
						 switch(message.header.getType()){
						 	case 0	: break; 
						 	case 3	:
						 		if(etiqueta.equals("contact")){
						 			message.content.contactResponse.addContact(contact);
						 		}
						 		break;
						 }
						 break;
				 }
				 evento = parser.next();
			}
		}catch (Exception ex){
			Log.e("xml-parser-error","error:"  + evento );
			throw ex;
		}
		
		return message;
	}
}
